package edu.thu.thss.yxy.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Properties;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;

import edu.thu.thss.yxy.audionotifier.AlertManager;
import edu.thu.thss.yxy.gui.event.CallInitiationEvent;
import edu.thu.thss.yxy.gui.event.CallPeerListener;
import edu.thu.thss.yxy.gui.event.CallPeerControlEvent;
import edu.thu.thss.yxy.sip.CallPeer;
import edu.thu.thss.yxy.sip.RegistrationState;
import edu.thu.thss.yxy.util.Logger;

public class GuiManager implements GuiCallback {
	private static final Logger logger = Logger.getLogger(GuiManager.class);

	private MainFrame mainFrame;
	private ConfigurationFrame configurationFrame;

	private ArrayList<CallPeerListener> callPeerListeners = null;
	private CallPeersTableModel callPeers = new CallPeersTableModel();

	public GuiManager() {
		// try {
		// UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		mainFrame = new MainFrame();
		configurationFrame = new ConfigurationFrame();
		callPeerListeners = new ArrayList<CallPeerListener>();

		initActionListeners();

		configurationFrame.setLocationRelativeTo(mainFrame);
		mainFrame.getPeersTable().setModel(callPeers);
		JOptionPane.setRootFrame(mainFrame);
	}

	private void initActionListeners() {
		mainFrame.getConfigItem().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				showConfigFrame();
			}
		});

		mainFrame.getExitItem().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				fireExitRequest();
			}
		});
		mainFrame.getDialButton().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				dialBtn_actionPerformed(evt);
			}
		});
		mainFrame.getContactBox().addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent evt) {
				contactBox_itemStateChange(evt);
			}
		});

		mainFrame.getAnswerBtn().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				answerBtn_actionPerformed(evt);
			}
		});
		mainFrame.getHangupBtn().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				hangupBtn_actionPerformed(evt);
			}
		});
		mainFrame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				fireExitRequest();
			}
		});
		configurationFrame.getSaveButton().addActionListener(
				new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						saveBtn_actionPerformed(evt);
					}
				});
	}

	public void setCommunicationActionsEnabled(boolean enabled) {
		mainFrame.getDialButton().setEnabled(enabled);
		mainFrame.getHangupBtn().setEnabled(enabled);
		mainFrame.getAnswerBtn().setEnabled(enabled);
	}

	public void addCallPeerListener(CallPeerListener callPeerListener) {
		callPeerListeners.add(callPeerListener);
	}

	public void removeCallPeerListener(CallPeerListener callPeerListener) {
		callPeerListeners.remove(callPeerListener);
	}

	//
	// ----------------- Event dispatching------------------------
	protected void dialBtn_actionPerformed(ActionEvent evt) {
		AlertManager.stopAllAlerts();

		String callee = mainFrame.getContactBox().getSelectedItem().toString();

		if (callee == null || callee.trim().length() < 1) {
			return;
		}

		CallInitiationEvent commEvt = new CallInitiationEvent(callee);
		for (CallPeerListener listener : callPeerListeners) {
			listener.handleDialRequest(commEvt);
		}
	}

	protected void contactBox_itemStateChange(ItemEvent evt) {
		if (((DefaultComboBoxModel) mainFrame.getContactBox().getModel())
				.getIndexOf(evt.getItem()) == -1)
			((DefaultComboBoxModel) mainFrame.getContactBox().getModel())
					.addElement(evt.getItem().toString().trim());
	}

	protected void answerBtn_actionPerformed(ActionEvent evt) {
		AlertManager.stopAllAlerts();
		if (callPeers.getRowCount() < 1)
			return;

		int selectedRow = mainFrame.getPeersTable().getSelectedRow();
		if (selectedRow < 0 || selectedRow > callPeers.getRowCount() - 1)
			return;
		CallPeer callPeer = callPeers.getCallPeerAt(selectedRow);
		CallPeerControlEvent commEvt = new CallPeerControlEvent(callPeer,
				callPeer.getDisplayName());
		for (CallPeerListener listener : callPeerListeners) {
			listener.handleAnswerRequest(commEvt);
		}
	}

	protected void hangupBtn_actionPerformed(ActionEvent evt) {
		AlertManager.stopAllAlerts();
		if (callPeers.getRowCount() < 1)
			return;

		int selectedRow = mainFrame.getPeersTable().getSelectedRow();
		if (selectedRow < 0 || selectedRow > callPeers.getRowCount() - 1)
			return;
		CallPeer callPeer = callPeers.getCallPeerAt(selectedRow);
		CallPeerControlEvent commEvt = new CallPeerControlEvent(callPeer,
				callPeer.getDisplayName());
		for (CallPeerListener listener : callPeerListeners) {
			listener.handleHangupRequest(commEvt);
		}
	}

	protected void saveBtn_actionPerformed(ActionEvent evt) {
		// check if properties are still being edited
		if (configurationFrame.getPropertiesTable().isEditing())
			configurationFrame.getPropertiesTable().getCellEditor()
					.stopCellEditing();
		for (CallPeerListener listener : callPeerListeners) {
			listener.handlePropertiesSaveRequest();
		}
		configurationFrame.dispose();
	}

	public void fireExitRequest() {
		for (CallPeerListener listener : callPeerListeners) {
			listener.handleExitRequest();
		}
	}

	public void setGlobalStatus(RegistrationState statusCode, String reason) {
		if (statusCode == RegistrationState.REGISTERED) {
			mainFrame.getRegistrationLabel().setForeground(Color.green);
			mainFrame.getRegistrationLabel().setText(statusCode.getStateName());
			mainFrame.getRegistrationAddressLabel().setForeground(Color.green);
			mainFrame.getRegistrationAddressLabel().setText(reason);
		} else if (statusCode == RegistrationState.REGISTERING) {
			mainFrame.getRegistrationLabel().setForeground(Color.yellow);
			mainFrame.getRegistrationLabel().setText(statusCode.getStateName());
			mainFrame.getRegistrationAddressLabel().setForeground(Color.yellow);
			mainFrame.getRegistrationAddressLabel().setText(reason);
		} else if (statusCode == RegistrationState.INIT) {
			mainFrame.getRegistrationLabel().setForeground(Color.red);
			mainFrame.getRegistrationLabel().setText(statusCode + " ");
			mainFrame.getRegistrationAddressLabel().setForeground(Color.yellow);
			mainFrame.getRegistrationAddressLabel().setText(reason);
		} else {
			mainFrame.getRegistrationLabel().setForeground(Color.red);
			mainFrame.getRegistrationLabel().setText(statusCode.getStateName());
		}
	}

	public void showMainFrame() {
		mainFrame.setVisible(true);
	}

	public void showConfigFrame() {
		configurationFrame.setVisible(true);
	}
	
	public void setProperties(Properties properties) {
		configurationFrame.setProperties(properties);
	}
	
	public void addVisualComponent(Component vComp)
    {
        if (vComp == null)
            return;
        else
            mainFrame.getVideoPanel().add(vComp);
        mainFrame.getVideoPanel().updateUI();
    }

    public void addControlComponent(Component cComp)
    {
        if (cComp == null)
            return;
        else
        	mainFrame.getVideoPanel().add(cComp);
        mainFrame.getVideoPanel().updateUI();
    }

    public void removePlayerComponents()
    {
    	mainFrame.getVideoPanel().removeAll();
    	mainFrame.getVideoPanel().updateUI();
    }
    
	public void addCallPeer(CallPeer callPeer) {
		callPeer.setCallback(this);
		callPeers.addCallPeer(callPeer);
		Integer peerId = Integer.parseInt(callPeer.getPeerID());
		mainFrame.getPeersTable().setRowSelectionInterval(
				callPeers.findIndex(peerId), callPeers.findIndex(peerId));
	}

	public void updateCallPeer(CallPeer callPeer) {
		callPeers.update(callPeer);
	}

	public void removeCallPeer(CallPeer callPeer) {
		callPeers.remove(callPeer);
	}

	public void startAlert(String alertResourceName) {
		try {
			AlertManager.startAlert(alertResourceName);
		} catch (Throwable ex) {
			logger.info("Couldn't play alert");
		}
	}

	public void stopAlert(String alertResourceName) {
		try {
			AlertManager.stopAlert(alertResourceName);
		} catch (Throwable ex) {
			logger.info("Couldn't stop alert");
		}
	}

	public void showUp() {
		mainFrame.showUp();
	}
}
